package com.gitee.hermer.engine.jars.core.loader.event.listener;

import java.io.File;
import java.util.Date;
import java.util.concurrent.TimeoutException;

import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

import com.gitee.hermer.boot.jee.commons.utils.DateUtils;
import com.gitee.hermer.boot.jee.commons.verify.Assert;
import com.gitee.hermer.engine.jars.app.sdk.EngineAppClassLoader;
import com.gitee.hermer.engine.jars.core.app.domain.EngineAppContext;
import com.gitee.hermer.engine.jars.core.context.IEngineAppContext;
import com.gitee.hermer.engine.jars.core.context.domain.EngineAppInfoContext;
import com.gitee.hermer.engine.jars.core.context.ex.EngineAppIllegalLoaderStateException;
import com.gitee.hermer.engine.jars.core.context.impl.EngineAppContextImpl.EngineAppLoaderState;
import com.gitee.hermer.engine.jars.core.event.listener.EngineEventListener;
import com.gitee.hermer.engine.jars.core.execute.EngineExecuteCallable;
import com.gitee.hermer.engine.jars.core.execute.EngineExecuteRunnable;
import com.gitee.hermer.engine.jars.core.execute.EngineExecuteThread.LifeCycle;
import com.gitee.hermer.engine.jars.core.execute.callback.EventCallableResult;
import com.gitee.hermer.engine.jars.core.execute.manage.IEngineExecutePoolManager;
import com.gitee.hermer.engine.jars.core.loader.EngineAppBeanScanner;
import com.gitee.hermer.engine.jars.core.loader.event.EngineAppDestroyEvent;
import com.gitee.hermer.engine.jars.core.loader.event.EngineAppInitializationEvent;
import com.gitee.hermer.engine.jars.core.loader.release.EngineAppReleaseSortArrayList;
import com.gitee.hermer.engine.jars.core.loader.release.IReleaseHandle;
import com.gitee.hermer.engine.jars.dependent.thread.pool.callback.CallableResult;

@Component
public class EngineAppInitializationEventListener extends EngineEventListener<EngineAppInitializationEvent> implements ApplicationEventPublisherAware{

	@Autowired
	private IEngineExecutePoolManager executePoolManager;

	@Autowired
	private IEngineAppContext engineAppContext;	

	@Autowired
	private EngineAppBeanScanner scanner;

	@Autowired
	private EngineAppReleaseSortArrayList engineAppReleaseHandle;

	@Autowired
	private ApplicationEventPublisher eventPublisher;



	@Override
	public void onEvent(EngineAppInitializationEvent event) {
		try{
			EngineAppClassLoader classLoader = scanner.getClassLoader((File) event.getSource(),parentContext.getClassLoader(),event.getCacheKey());
			executePoolManager.executeAsyn(new EngineExecuteCallable<Boolean>(parentContext,classLoader,event.getCacheKey(),LifeCycle.INITIALIZATION) {

				@Override
				public Boolean onExecute() throws Throwable {
					try{
						File jarFile = (File) event.getSource();
						engineAppContext.updateEngineAppLoaderState(cacheKey,  EngineAppLoaderState.BEGIN_INIT);
						info("线程ID[%s]|线程名[%s]|项目[%s]|容器路径[%s]|初始化中...",this.getId(),this.getName(),event.getCacheKey(),jarFile.getPath());
						context = scanner.springClassLoader((EngineAppClassLoader)this.classLoader);
						Assert.notNull(context);
						info("线程ID[%s]|线程名[%s]|项目[%s]|容器初始化完毕！",getId(),getName(),event.getCacheKey());
						engineAppContext.updateEngineAppLoaderState(cacheKey,  EngineAppLoaderState.END_INIT);
						engineAppContext.updateEngineAppLoaderState(cacheKey,  EngineAppLoaderState.RUN_ING);
						engineAppContext.register(cacheKey, new EngineAppInfoContext(
								cacheKey, jarFile.getName(), event.getFileMd5(), DateUtils.getDateTimeFormat(new Date(jarFile.lastModified())), 
								context, parentContext, new EngineExecuteRunnable(new EngineAppContext(context, parentContext),cacheKey,null,LifeCycle.DESTROY) {

									@Override
									public Void onExecute() {
										for (IReleaseHandle iReleaseHandle : engineAppReleaseHandle.getSortOrderReleaseHandle()) {
											try{
												iReleaseHandle.release(this);
											}catch (Exception e) {
												error(e.getMessage(),e);
											}
										}
										return null;
									}
								}));
						return true;
					}catch (Throwable e) {
						if(e instanceof EngineAppIllegalLoaderStateException){
							error(e.getMessage(),e);
						}else{
							throw e;
						}
					}
					return false;
				}
			},new EventCallableResult<Boolean>(event){
				@Override
				public void onCall(Boolean value) throws Exception {
					boolean Success = BooleanUtils.toBooleanDefaultIfNull(value, false);
					info("事件ID[%s]|容器事件[%s]执行完毕！启动状态[%s] -> 当前时间 -> [%s]",event.getID(),event,Success,DateUtils.getCurrentTime());
				}
				@Override
				public void onError(Throwable e) {
					// 初始化不成功销毁容器状态
					EngineAppInitializationEvent initializationEvent = (EngineAppInitializationEvent) event;
					EngineAppDestroyEvent destroyEvent = new EngineAppDestroyEvent(initializationEvent.getProject(), initializationEvent.getVersion(), classLoader);
					EngineAppInitializationEventListener.this.eventPublisher.publishEvent(destroyEvent);
					super.onError(e);
					try{ onCall(null); }catch (Exception e2) { };
				}
			});
		}catch (Throwable e) {
			error(e.getMessage(),e);
		}
	}



	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.eventPublisher = applicationEventPublisher;
	}
}




